package com.toy.core.security.authenticate;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;

import com.toy.core.config.SysConfig;
import com.toy.core.security.Authentication;
import com.toy.core.security.GrantedAuthority;
import com.toy.core.security.GrantedAuthorityImpl;
import com.toy.core.security.UsernamePasswordAuthentication;
import com.toy.core.security.concurrent.SessionRegistry;
import com.toy.core.security.concurrent.SessionToken;
import com.toy.core.security.context.SecurityContextHolder;
import com.toy.core.security.exception.AuthenticationException;
import com.toy.core.security.userdetails.UserDetail;
import com.toy.core.security.userdetails.UserDetailsService;

public class AuthenticationProviderImpl implements AuthenticationProvider {
	
	private SessionRegistry sessionRegistry;
	
	@Autowired
	private SysConfig sysConfig;
	
	public Authentication authenticate(Authentication authentication)
			throws AuthenticationException {
		
		UserDetailsService userDetailsService = sysConfig.getStorageUserDetailsService();
		
		UserDetail userDetails = null;
		
		if ( authentication.isAuthenticated()){
			userDetails = userDetailsService.getByUsername((String)authentication.getPrincipal());
		}else{
			userDetails = userDetailsService.validate((String) authentication
					.getPrincipal(), (String) authentication.getCredentials());
		}
		
		if ( userDetails.isAccountEnabled()){
			throw new AuthenticationException(AuthenticationException.CODE_DisabledException);
		}
		
		if ( userDetails.isAccountExpired()){
			throw new AuthenticationException(AuthenticationException.CODE_AccountExpiredException);
		}
		
		if ( userDetails.isAccountLocked()){
			throw new AuthenticationException(AuthenticationException.CODE_LockedException);
		}
		
		if ( userDetails.isCredentialsExpired()){
			throw new AuthenticationException(AuthenticationException.CODE_CredentialsExpiredException);
		}
		String ticket = (String)authentication.getAttribute(Authentication.ATTR_TICKET);
		SessionToken sessionToken = null;
		if (StringUtils.isNotBlank(ticket)){
			sessionToken = sessionRegistry.getByToken(ticket);
		}else{
			sessionToken = sessionRegistry.registerSession(authentication);
		}
		authentication = createSuccessAuthentication(authentication,userDetails,sessionToken);
		SecurityContextHolder.getContext().setAuthentication(authentication);
		return authentication;
	}
	
	protected Authentication createSuccessAuthentication(Authentication authentication,
	        UserDetail user,SessionToken sessionToken) {
			List<GrantedAuthority> list = new ArrayList<GrantedAuthority>();
			GrantedAuthority authority = new GrantedAuthorityImpl(GrantedAuthority.SP_AUTHORITY_ALL_USER);
			list.add(authority);
			if ( user.getAuthorities() != null && user.getAuthorities().length > 0 ){
				list.addAll(Arrays.asList(user.getAuthorities()));
			}
	        UsernamePasswordAuthentication result = new UsernamePasswordAuthentication((String)authentication.getPrincipal(),
	        		(String)authentication.getCredentials(), list.toArray(new GrantedAuthority[list.size()]));
	        result.setDetails(authentication.getDetails());
	        result.setAttribute(Authentication.ATTR_TICKET, sessionToken.getToken());
	        return result;
	  }
	
	public void setSessionRegistry(SessionRegistry sessionRegistry) {
		this.sessionRegistry = sessionRegistry;
	}
}
